package com.lemon.exam.common.redis.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import reactor.core.publisher.Mono;

import java.time.Duration;
import java.util.Arrays;

/**
 * Redis 字符串操作 类对象
 *
 * @author Lemon
 * @since 2025/7/4 17:57
 */
public final class StringOperations extends BaseOperations {
    public StringOperations(ObjectMapper objectMapper, ReactiveRedisTemplate<String, Object> template) {
        super(objectMapper, template);
    }

    /**
     * 设置缓存
     *
     * @param key   缓存key
     * @param value 缓存value
     * @return 是否成功
     */
    public Mono<Boolean> set(String key, Object value) {
        return withRetry(
                template.opsForValue().set(key, value),
                "redis string set key: %s".formatted(key)
        ).onErrorResume(err -> Mono.just(false));
    }

    /**
     * 带超时的设置缓存
     *
     * @param key     缓存key
     * @param value   缓存value
     * @param timeout 超时时间
     * @return 是否成功
     */
    public Mono<Boolean> set(String key, Object value, Duration timeout) {
        return withRetry(
                template.opsForValue().set(key, value, timeout),
                "redis string set key: %s".formatted(key)
        ).onErrorResume(err -> Mono.just(false));
    }

    /**
     * 获取缓存
     *
     * @param key   缓存key
     * @param clazz 缓存value类型
     * @param <T>   缓存value类型
     * @return 缓存value
     */
    public <T> Mono<T> get(String key, Class<T> clazz) {
        return withRetry(
                template.opsForValue().get(key).mapNotNull(toGeneric(clazz)),
                "redis string get key: %s".formatted(key)
        ).onErrorResume(err -> Mono.empty());
    }

    /**
     * 删除缓存
     *
     * @param keys 缓存key
     * @return 是否成功
     */
    public Mono<Boolean> del(String... keys) {
        return withRetry(
                template.delete(keys).map(v -> v != null && v == keys.length),
                "redis string del key: %s".formatted(Arrays.toString(keys))
        ).onErrorResume(err -> Mono.just(false));
    }

    /**
     * 判断缓存是否存在
     *
     * @param key 缓存key
     * @return 是否存在
     */
    public Mono<Boolean> has(String key) {
        return withRetry(
                template.hasKey(key),
                "redis string has key: %s".formatted(key)
        ).onErrorResume(err -> Mono.just(false));
    }

    /**
     * 递增缓存
     *
     * @param key   缓存key
     * @param delta 递增值
     * @return 递增后的值
     */
    public Mono<Long> increment(String key, long delta) {
        return withRetry(
                template.opsForValue().increment(key, delta),
                "redis string increment key: %s".formatted(key)
        ).onErrorResume(err -> Mono.just(0L));
    }

    /**
     * 设置缓存过期时间
     *
     * @param key     缓存key
     * @param timeout 过期时间
     * @return 是否成功
     */
    public Mono<Boolean> expire(String key, Duration timeout) {
        return withRetry(
                template.expire(key, timeout),
                "redis string expire key: %s".formatted(key)
        ).onErrorResume(err -> Mono.just(false));
    }
}
